package com.ruyiadmin.springcloud.producer.controller.system;

import com.alibaba.fastjson.JSON;
import com.ruyiadmin.springcloud.producer.common.annotations.system.Log;
import com.ruyiadmin.springcloud.producer.common.annotations.system.Permission;
import com.ruyiadmin.springcloud.producer.common.beans.system.SystemCacheConfig;
import com.ruyiadmin.springcloud.producer.common.components.core.RuYiRedisComponent;
import com.ruyiadmin.springcloud.producer.common.core.business.enums.OperationType;
import com.ruyiadmin.springcloud.producer.common.core.system.entities.ActionResult;
import com.ruyiadmin.springcloud.producer.common.core.system.entities.QueryResult;
import com.ruyiadmin.springcloud.producer.common.exceptions.RuYiAdminCustomException;
import com.ruyiadmin.springcloud.producer.domain.dto.system.SysCodeTableDTO;
import com.ruyiadmin.springcloud.producer.domain.entity.system.SysCodeTable;
import com.ruyiadmin.springcloud.producer.service.iservices.system.ISysCodeTableService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据字典表 前端控制器
 * </p>
 *
 * @author RuYiAdmin
 * @since 2022-07-12
 */
@RestController
@RequestMapping("/CodeTableManagement")
@Api(tags = "系统数据字典管理服务")
@RequiredArgsConstructor
public class SysCodeTableController {

    //region 字典服务私有属性

    private final RuYiRedisComponent redisUtils;
    private final SystemCacheConfig systemCacheConfig;
    private final ISysCodeTableService codeTableService;
    private final ModelMapper modelMapper;

    //endregion

    //region 查询字典列表

    @PostMapping("/Post")
    @ApiOperation(value = "查询字典列表")
    @Log(OperationType = OperationType.QueryList)
    @Permission(permission = "code:query:list")
    public QueryResult<SysCodeTableDTO> getCodeTreeNodes() throws ExecutionException, InterruptedException {
        CompletableFuture<QueryResult<SysCodeTableDTO>> future =
                CompletableFuture.supplyAsync(this.codeTableService::getCodeTreeNodes);
        return future.get();
    }

    //endregion

    //region 获取字典信息

    @GetMapping("/GetById/{id}")
    @ApiOperation(value = "获取字典信息")
    @Log(OperationType = OperationType.QueryEntity)
    @Permission(permission = "code:query:list")
    public ActionResult getById(@PathVariable("id") String id) throws ExecutionException, InterruptedException {
        CompletableFuture<ActionResult> future = CompletableFuture.supplyAsync(() -> {
            Object value = this.redisUtils.get(this.systemCacheConfig.getCodeTableCacheName());
            List<SysCodeTableDTO> codeTables = JSON.parseArray(value.toString(), SysCodeTableDTO.class);
            return ActionResult.success(codeTables.stream()
                    .filter(t -> t.getId().equals(id))
                    .collect(Collectors.toList()).get(0));
        });
        return future.get();
    }

    //endregion

    //region 新增字典信息

    @PostMapping("/Add")
    @ApiOperation(value = "新增字典信息")
    @Log(OperationType = OperationType.AddEntity)
    @Permission(permission = "code:add:entity")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult addCodeTable(@Valid @RequestBody SysCodeTable codeTable) {
        ActionResult actionResult = ActionResult.success(this.codeTableService.save(codeTable));

        //region 数据一致性维护

        Object value = this.redisUtils.get(systemCacheConfig.getCodeTableCacheName());
        List<SysCodeTableDTO> codeTables = JSON.parseArray(value.toString(), SysCodeTableDTO.class);

        SysCodeTableDTO codeTableDTO = this.modelMapper.map(codeTable, SysCodeTableDTO.class);
        codeTables.add(codeTableDTO);

        this.redisUtils.set(this.systemCacheConfig.getCodeTableCacheName(), JSON.toJSONString(codeTables));

        //endregion

        return actionResult;
    }

    //endregion

    //region 修改字典信息

    @PutMapping("/Put")
    @ApiOperation(value = "修改字典信息")
    @Log(OperationType = OperationType.EditEntity)
    @Permission(permission = "code:edit:entity")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult editCodeTable(@Valid @RequestBody SysCodeTable codeTable) {
        ActionResult actionResult = ActionResult.success(this.codeTableService.updateById(codeTable));

        //region 数据一致性维护

        Object value = this.redisUtils.get(systemCacheConfig.getCodeTableCacheName());
        List<SysCodeTableDTO> codeTables = JSON.parseArray(value.toString(), SysCodeTableDTO.class);

        //删除旧数据
        for (Iterator<SysCodeTableDTO> iterator = codeTables.iterator(); iterator.hasNext(); ) {
            SysCodeTableDTO element = iterator.next();
            if (element.getId().equals(codeTable.getId())) {
                iterator.remove();
                break;
            }
        }

        //数据转换
        SysCodeTableDTO codeTableDTO = this.modelMapper.map(codeTable, SysCodeTableDTO.class);
        codeTables.add(codeTableDTO);

        this.redisUtils.set(this.systemCacheConfig.getCodeTableCacheName(), JSON.toJSONString(codeTables));

        //endregion

        return actionResult;
    }

    //endregion

    //region 批量删除字典信息

    @DeleteMapping("/DeleteRange/{ids}")
    @ApiOperation(value = "批量删除字典信息")
    @Log(OperationType = OperationType.DeleteEntity)
    @Permission(permission = "code:del:entities")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult deleteRange(@PathVariable("ids") String ids) {
        //字典删除检测
        this.deleteCheck(ids);
        //删除数据
        List<String> array = Arrays.asList(ids.split(","));
        ActionResult actionResult = ActionResult.success(this.codeTableService.removeByIds(array));

        //region 数据一致性维护

        Object value = this.redisUtils.get(systemCacheConfig.getCodeTableCacheName());
        List<SysCodeTableDTO> codeTables = JSON.parseArray(value.toString(), SysCodeTableDTO.class);

        for (String item : array) {
            for (Iterator<SysCodeTableDTO> iterator = codeTables.iterator(); iterator.hasNext(); ) {
                SysCodeTableDTO element = iterator.next();
                if (element.getId().equals(item)) {
                    iterator.remove();
                    break;
                }
            }
        }

        this.redisUtils.set(this.systemCacheConfig.getCodeTableCacheName(), JSON.toJSONString(codeTables));

        //endregion

        return actionResult;
    }

    //endregion

    //region 获取字典子集

    @GetMapping("/GetChildrenByCode/{code}")
    @ApiOperation(value = "获取字典子集")
    @Log(OperationType = OperationType.QueryEntity)
    public ActionResult getChildrenByCode(@PathVariable("code") String code) throws ExecutionException, InterruptedException {
        CompletableFuture<ActionResult> future = CompletableFuture.supplyAsync(() -> {
            Object value = this.redisUtils.get(this.systemCacheConfig.getCodeTableCacheName());
            List<SysCodeTableDTO> codeTables = JSON.parseArray(value.toString(), SysCodeTableDTO.class);

            List<SysCodeTableDTO> root = codeTables.stream().
                    filter(t -> !StringUtils.isEmpty(t.getCode())).
                    filter(t -> t.getCode().equals(code)).
                    collect(Collectors.toList());

            if (root.size() > 0) {
                SysCodeTableDTO current = root.get(0);
                List<SysCodeTableDTO> children = codeTables.stream().
                        filter(t -> !StringUtils.isEmpty(t.getParentId())).
                        filter(t -> t.getParentId().equals(current.getId())).
                        collect(Collectors.toList());
                return ActionResult.success(children);
            } else {
                return ActionResult.success(null);
            }
        });
        return future.get();
    }

    //endregion

    //region 字典删除检测

    /**
     * 字典删除检测
     *
     * @param ids 编号数组
     */
    private void deleteCheck(String ids) {
        Object value = this.redisUtils.get(systemCacheConfig.getCodeTableCacheName());
        List<SysCodeTableDTO> codeTables = JSON.parseArray(value.toString(), SysCodeTableDTO.class);

        String[] array = ids.split(",");
        //删除校验
        for (String item : array) {
            int size = (int) codeTables.stream().
                    filter(t -> !StringUtils.isEmpty(t.getParentId())).
                    filter(t -> t.getParentId().equals(item)).count();
            if (size > 0) {
                throw new RuYiAdminCustomException("code contains subitems,can not be deleted");
            }
        }

    }

    //endregion

}
